import { batch, createSignal, onCleanup, onMount } from "solid-js";
import { createStore } from "solid-js/store";

const getMediaRecorder = () =>
  new Promise<MediaRecorder>((resolve, reject) => {
    if (navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices.getUserMedia({ audio: true }).then(
        (stream) => {
          resolve(new MediaRecorder(stream));
        },
        (e) => {
          console.error("授权失败", e);
          reject(new Error("授权失败"));
        },
      );
    } else {
      reject(new Error("浏览器不支持 getUserMedia"));
    }
  });

type Options = {
  onOk: (audio: Blob) => void;
  onError?: (e: ErrorEvent) => void;
};

const useAudioRecorder = ({ onOk, onError }: Options) => {
  const [audioChunks, setAudioChunks] = createStore<Blob[]>([]);
  const [audioStatus, setAudioStatus] = createSignal<RecordingState>("inactive");

  let audioRecorder: MediaRecorder | null = null;

  const handleStart = () => {
    batch(() => {
      setAudioChunks(() => []);
      setAudioStatus("recording");
    });
  };

  const handleDataAvailable = (e: BlobEvent) => {
    setAudioChunks((chunks) => [...chunks, e.data]);
  };

  const handleStop = () => {
    const blob = new Blob(audioChunks, {
      type: "audio/ogg; codecs=opus",
    });
    batch(() => {
      setAudioChunks(() => []);
      setAudioStatus("inactive");
    });

    onOk(blob);
  };

  const handleError = (e: ErrorEvent) => {
    onError?.(e);
    batch(() => {
      setAudioChunks(() => []);
      setAudioStatus("inactive");
    });
  };

  const handlePause = () => {
    setAudioStatus("paused");
  };

  const handleResume = () => {
    setAudioStatus("recording");
  };

  onMount(() => {
    getMediaRecorder()
      .then((ar) => {
        ar.onstart = handleStart;
        ar.ondataavailable = handleDataAvailable;
        ar.onstop = handleStop;
        ar.onpause = handlePause;
        ar.onresume = handleResume;
        ar.onerror = handleError;
        audioRecorder = ar;
      })
      .catch((err) => {
        onError?.(err);
      });

    onCleanup(() => {
      audioRecorder?.stop();
    });
  });

  const start = () => {
    audioRecorder?.start();
  };

  const stop = () => {
    audioRecorder?.stop();
  };

  const pause = () => {
    audioRecorder?.pause();
  };

  const resume = () => {
    audioRecorder?.resume();
  };

  return { start, stop, pause, resume, status: audioStatus };
};

export default useAudioRecorder;
